package sopraim.model;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import sopraim.entity.Location;
import sopraim.entity.RequestFriends;
import sopraim.entity.Status;
import sopraim.entity.User;
import sopraim.exceptions.*;

public class UserDAO {
    
    private SessionFactory factory;
    
    public UserDAO(SessionFactory factory) {
        this.factory = factory;
    }
    
    /**
     *
     * @param usernameToFind
     * @return user if find, (first of the list) or null if not find
     */
    public User findByLogin(String usernameToFind) {
        Session session = factory.getCurrentSession();
        session.beginTransaction();
        //named parameter (preferred)
        Query q = session.createQuery("from User where username = :name");
        q.setString("name", usernameToFind);
        User u = null;
        if (q.iterate().hasNext()) {
            u = (User) q.iterate().next();
        }
        return u;
    }
    
    public User findById(int user_id) {
        Session session = null;
        User user = null;
        try {
            session = factory.getCurrentSession();
            session.beginTransaction();
            user = (User) session.load(User.class,
                    user_id);
            Hibernate.initialize(user);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (session != null && session.isOpen()) {
                session.close();
            }
        }
        return user;
    }
    
    public List<String> findAllUsernames() {
        Session session = factory.getCurrentSession();
        session.beginTransaction();
        List<String> res = new ArrayList<String>();
        List list = session.createQuery("from User").list();
        Iterator it = list.iterator();
        while (it.hasNext()) {
            User user = (User) it.next();
            res.add(user.getUsername());
        }
        return res;
    }
    public void updateUserStatus(User u, Status newStatus) {
        Session session = factory.getCurrentSession();
        session.beginTransaction();
        u.setStatus(newStatus);
        session.merge(u);
        session.getTransaction().commit();
        
    }
    
    public void updateUserPassword(User u, String oldPassword, String newPassword) throws WrongPasswordException {
        Session session = factory.getCurrentSession();
        session.beginTransaction();
        // test the old password to change it
        if (u.getPassword().equals(oldPassword)) {
            u.setPassword(newPassword);
        } else {
            throw new WrongPasswordException();
        }
        session.update(u);
        session.getTransaction().commit();
    }
    
    public void setLocation(User u, Location newlocation) {
        Session session = factory.getCurrentSession();
        session.beginTransaction();
        u.setLocation(newlocation);
        session.update(u);
        session.getTransaction().commit();
    }
    
    public void getUserDetails(User userToFind) {
        
    }
    
    public void requestFriends(User userAsker, User userAnswerer) throws AlreadyFriendsException {
        if (areFriends(userAsker, userAnswerer)) {
            throw new AlreadyFriendsException();
        } else {
            Session session = factory.getCurrentSession();
            session.beginTransaction();
            RequestFriends r = new RequestFriends();
            r.setUserAsker(userAsker);
            r.setUserAnswer(userAnswerer);
            r.setViewed(false);
            r.setAnswered(false);
            r.setAccepted(false);
            session.save(r);
            session.getTransaction().commit();
        }
        
    }
    
    public void answerRequest(User userAsk, User userAns, Boolean answer) {
        Session session = factory.getCurrentSession();
        session.beginTransaction();
        // update the RequestFriends table
        Query q = session.createQuery("from RequestFriends where userAsker = :userAsk and userAnswer = :userAns")
                .setParameter("userAsk", userAsk)
                .setParameter("userAns", userAns);
        RequestFriends r = null;
        if (q.iterate().hasNext()) {
            r = (RequestFriends) q.iterate().next();
            r.setAnswered(true);
            r.setAccepted(answer);
            session.update(r);
        }
        // if the answeris true => add the friend relation to friends table
        if (answer) {
            try {
                
                userAsk.getFriends().add(userAns);
                userAns.getFriends().add(userAsk);
                session.merge(userAsk);
                session.merge(userAns);
                System.out.print("asker : "+userAns.getFriends()+"\n\n");
                System.out.print("asker : "+userAsk.getFriends()+"\n\n");
            } catch (Exception e) {
                System.out.print(e.getMessage()+":"+e.getCause());
            }
        }
        session.getTransaction().commit();
    }
    
    public void deleteFriends(User u, User friendToDelete) {
       /* Session session = factory.getCurrentSession();
        session.beginTransaction();
        Set<User> friends = u.getFriends() ;
        Set<User> friends2 = friendToDelete.getFriends() ;
        /*
        try{
        Iterator<User> it = friends.iterator();
        while(it.hasNext()){
        User c= it.next();
        if(c.getId() == friendToDelete.getId()){
        friends.remove(c);
        session.delete(friends);
        break;
        }
        }
        Iterator<User> it2 = friends2.iterator();
        while(it2.hasNext()){
        User c= it2.next();
        if(c.getId() == u.getId()){
        friends2.remove(c);
        session.merge(friends2);
        break;
        }
        }
        }
        catch(Exception e){
        System.err.println(e.getMessage());
        }
        System.err.println("removed");
        session.flush();
        session.getTransaction().commit();
        */
    }
    
    
    
    public boolean areFriends(User u1, User u2) {
        boolean yes = false;
        for(User f:u1.getFriends()){
            if(f.getUsername().equals(u2.getUsername())){
                yes = true;
                break;
            }
        }
        return yes;
    }
    
    public HashSet<User> getNotifFriendsRequest(User u) {
        // pour afficher sur le client de U les demandes
        // d'amis qui lui sont addressées
        Session session = factory.getCurrentSession();
        session.beginTransaction();
        List list = session.createQuery("from RequestFriends as rf where rf.userAnswer = :userAns and rf.viewed = false")
                .setParameter("userAns", u).list();
        HashSet<User> s = new HashSet<User>();
        RequestFriends r = null;
        Iterator it = list.iterator();
        while(it.hasNext()) {
            r = (RequestFriends) it.next();
            s.add(r.getUserAsker());
            r.setViewed(true);
            session.update(r);
        }
        session.getTransaction().commit();
        return s;
    }
    
    public HashSet<User> getNotifFriendsRequestNotAnswered(User u) {
        // pour afficher sur le client de U les demandes
        // d'amis qui lui sont addressées non encore répondue
        Session session = factory.getCurrentSession();
        session.beginTransaction();
        List list = session.createQuery("from RequestFriends as rf where rf.userAnswer = :userAns and rf.answered = false")
                .setParameter("userAns", u).list();
        HashSet<User> s = new HashSet<User>();
        RequestFriends r = null;
        Iterator it = list.iterator();
        while (it.hasNext()) {
            r = (RequestFriends) it.next();
            s.add(r.getUserAsker());
            r.setViewed(true);
            session.update(r);
            //System.out.print("Ok "+r.getUserAsker().getUsername());
        }
        for(User us : s){
            System.err.println("fr req "+us.getUsername());
        }
        session.getTransaction().commit();
        return s;
    }
    
    
    
    public HashSet<User> getNotifFriendsAnswer(User u) {
        // pour afficher au client les réponses de demande d'amis que a fait
        Session session = factory.getCurrentSession();
        session.beginTransaction();
        List list = session.createQuery("from RequestFriends as rf where userAsker = :userAsk and rf.answered=true")
                .setParameter("userAsk", u).list();
        HashSet<User> s = new HashSet<User>();
        RequestFriends r = null;
        Iterator it = list.iterator();
        while (it.hasNext()) {
            r = (RequestFriends) it.next();
            s.add(r.getUserAnswer());
        }
        session.getTransaction().commit();
        return s;
    }
    
}
